﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace KSATouch
{
    enum FilterType { SimpleLowPass,Average};
    /// <summary>
    /// This class is meant to offer a general filtering system for data. This is used to apply a lowpass filter to our current blob positions.
    /// </summary>
    public class InputFilter
    {
        private static InputFilter instance;
        private Dictionary<string, List<double>> items;
        private FilterType inputFilterType;

        internal FilterType InputFilterType
        {
            get { return inputFilterType; }
            set { inputFilterType = value; }
        }

        private double inputCoefficient;

        public double InputCoefficient
        {
            get { return inputCoefficient; }
            set { inputCoefficient = value; }
        }

        public static InputFilter GetInstance()
        {
            if(instance != null)
            {
                return instance;
            }
            else
            {
                instance = new InputFilter();
                return instance;
         
           }
        }
        /// <summary>
        /// Instantiates a new input filter. Used to apply lowpass filters or other filters to smooth jitter
        /// </summary>
        private InputFilter()
        {
            items = new Dictionary<string, List<double>>();
            inputFilterType = FilterType.SimpleLowPass;
            inputCoefficient = 0.5;
        }

        /// <summary>
        /// Returns a filtered value for a given name
        /// </summary>
        /// <param name="name">name of vaue to retrieve</param>
        /// <param name="value">input value of current frame</param>
        /// <returns></returns>
        public double GetFilteredValue(string name, double value)
        {
            // add the value to the expected collection, and then get back that collection
            List<double> list = GetList(name, value);
            double filteredValue = value;
            // Based on the filter type, go through the collection and return the correct value
            switch (inputFilterType)
            {
                case FilterType.SimpleLowPass:
                    {
                        // courtesy of tutorial from: http://haylexstudios.com/DevHelper.aspx
                        // On = On-1 + C(R – On-1) where:
                        // R = Raw value sampled from the accelerometer
                        // C = Coefficient used to control the filter
                        // On-1 = The last calculated sample value
                        // On = The current calculated sample value
                        if(list.Count > 0)
                        {
                            filteredValue = list.Last() + inputCoefficient * (value - list.Last());
                            list.Add(filteredValue);
                        }
                        else
                        {
                            list.Add(value);
                            // Note: We had no values to base on, so just add this to the list and return it
                            // We assigned it before we went into this switch statement, so no need to do it here.
                        }

                        break;
                    }
                case FilterType.Average:
                    {
                        filteredValue = ((list.Last() + value) / 2);
                        break;
                    }                
            }
            return filteredValue;
        }

        /// <summary>
        /// Returns the list of stored values
        /// </summary>
        /// <param name="name">name of settings to returh</param>
        /// <param name="value">new value which is being added</param>
        /// <returns></returns>
        private List<double> GetList(string name, double value)
        {
            List<double> list;
            if (items.Keys.Contains(name))
            {
                 list = items[name];
            }
            else
            {
                list = new List<double>();
                items.Add(name, list);
            }
            return list;
        }

    }
}
